// app/api/vendor-investigations/[investigationId]/attachments/route.ts import { NextRequest, NextResponse } from "next/server" import { promises as fs } from "fs" import path from "path" import { v4 as uuidv4 } from "uuid" import db from "@/db/db" import { vendorInvestigationAttachments } from "@/db/schema" import { eq } from "drizzle-orm"; type Ctx = { params: Promise<{ investigationId: string }> }; export async function POST( req: NextRequest, context: Ctx // ① 두 번째 인자를 통째로 받는다 ) { try { const { investigationId: idParam } = await context.params; // ② 여기서 await const investigationId = Number(idParam); if (!investigationId) { return NextResponse.json({ error: "Invalid investigation ID" }, { status: 400 }) } const formData = await req.formData() const file = formData.get("file") as File if (!file || file.size === 0) { return NextResponse.json({ error: "No file provided" }, { status: 400 }) } // 파일 크기 제한 (10MB) const maxSize = 10 * 1024 * 1024 if (file.size > maxSize) { return NextResponse.json({ error: `파일 크기가 ${maxSize / 1024 / 1024}MB를 초과합니다.` }, { status: 400 }) } // 지원하는 파일 타입 검증 const allowedTypes = [ 'application/pdf', 'application/msword', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'application/vnd.ms-excel', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'image/png', 'image/jpeg', 'image/jpg', 'image/gif' ] if (!allowedTypes.includes(file.type)) { return NextResponse.json({ error: "지원하지 않는 파일 형식입니다." }, { status: 400 }) } // 파일 저장 const arrayBuffer = await file.arrayBuffer() const buffer = Buffer.from(arrayBuffer) // 고유한 파일명 생성 const ext = path.extname(file.name) const uniqueName = `${uuidv4()}${ext}` // 업로드 디렉토리 생성 const uploadDir = path.join(process.cwd(), "public", "vendor-investigation", String(investigationId)) await fs.mkdir(uploadDir, { recursive: true }) const filePath = path.join(uploadDir, uniqueName) await fs.writeFile(filePath, buffer) // 파일 타입 결정 let attachmentType = "OTHER" if (file.type.includes("pdf")) { attachmentType = "REPORT" } else if (file.type.includes("image")) { attachmentType = "PHOTO" } else if ( file.type.includes("word") || file.type.includes("document") || file.name.toLowerCase().includes("report") ) { attachmentType = "DOCUMENT" } // DB에 파일 정보 저장 const [attachment] = await db.insert(vendorInvestigationAttachments).values({ investigationId, fileName: file.name, filePath: `/vendor-investigation/${investigationId}/${uniqueName}`, fileSize: file.size, mimeType: file.type, attachmentType: attachmentType as "REPORT" | "PHOTO" | "DOCUMENT" | "CERTIFICATE" | "OTHER", // uploadedBy: currentUserId, // 실제 사용자 ID로 설정 }).returning() return NextResponse.json({ success: true, attachment: { id: attachment.id, fileName: attachment.fileName, filePath: attachment.filePath, fileSize: attachment.fileSize, attachmentType: attachment.attachmentType } }) } catch (error) { console.error("파일 업로드 오류:", error) return NextResponse.json({ error: "파일 업로드 중 오류가 발생했습니다." }, { status: 500 }) } } // 첨부파일 삭제 export async function DELETE( req: NextRequest, { params }: { params: { investigationId: string } } ) { try { const { searchParams } = new URL(req.url) const attachmentId = searchParams.get("attachmentId") if (!attachmentId) { return NextResponse.json({ error: "Attachment ID required" }, { status: 400 }) } // DB에서 파일 정보 조회 const attachment = await db.query.vendorInvestigationAttachments.findFirst({ where: (attachments, { eq, and }) => and( eq(attachments.id, parseInt(attachmentId)), eq(attachments.investigationId, parseInt(params.investigationId)) ) }) if (!attachment) { return NextResponse.json({ error: "Attachment not found" }, { status: 404 }) } // 실제 파일 삭제 const fullPath = path.join(process.cwd(), "public", attachment.filePath) try { await fs.unlink(fullPath) } catch (error) { console.warn("파일 삭제 실패 (파일이 존재하지 않을 수 있음):", error) } // DB에서 레코드 삭제 await db.delete(vendorInvestigationAttachments) .where(eq(vendorInvestigationAttachments.id, parseInt(attachmentId))) return NextResponse.json({ success: true }) } catch (error) { console.error("파일 삭제 오류:", error) return NextResponse.json({ error: "파일 삭제 중 오류가 발생했습니다." }, { status: 500 }) } }